#include "osMutex.h"

#include "osCpu.h"

#if OS_ENABLE_MUTEX == 1

/*****************************************************************************
 * @function        vMutexInit
 * @brief 			初始化互斥锁.
 *  
 * @param[in] 		mutex 互斥锁.
 * 
 * @return 			None.	
 *
 * ***************************************************************************/
void vMutexInit(MUTEX_T *mutex)
{
    vEventInit(&mutex->event, eventTypeMutex);
    
    mutex->owner = (TASK_T *)0;
    mutex->ownerOriginPrio = OS_PRIO_COUNT;         // 正常的优先级是0-31，配置为32，无效优先级
    mutex->lockCount = 0;
}

/*****************************************************************************
 * @function        vMutexWait
 * @brief 			等待获取互斥锁.
 *  
 * @param[in] 		mutex 互斥锁.
 * @param[in]       timeout 超时时间.
 * 
 * @return 			获取结果. 	OS_NOERROR:获取成功
*                      OS_TIMEOUT  : 获取超时
 *
 * ***************************************************************************/
uint32_t vMutexWait(MUTEX_T *mutex, uint32_t timeout)
{
    uint32_t primask = vTaskEnterCritical();

    /* 无任务获取互斥锁*/
    if (mutex->lockCount == 0)
    {
        mutex->lockCount ++;
        mutex->owner = curTask;
        mutex->ownerOriginPrio = curTask->prio;     // 保存原始优先级
        
        vTaskExitCritical(primask);
        return OS_NOERROR;
    }
    else 
    {
        /* 互斥锁所有者 再次获取互斥锁*/
        if (curTask == mutex->owner)
        {
            mutex->lockCount++;
            vTaskExitCritical(primask);
            return OS_NOERROR;
        }
        /* 其他任务请求获取互斥锁*/
        else
        {
            /* 优先级继承*/
            if (curTask->prio < mutex->owner->prio)
            {
                /* 任务处于就绪态--提升优先级*/
                if (mutex->owner->state == OS_TASK_STA_READY)
                {
                    /* 将任务从就绪队列中移除，修改优先级后再添加进就绪队列中！！！*/
                    vTaskReadyListDel(mutex->owner);
                    mutex->owner->prio = curTask->prio;
                    vTaskReadyListAdd(mutex->owner);
                }
                /* 任务处于其他等待队列中,直接修改优先级*/
                else 
                {
                    mutex->owner->prio = curTask->prio;
                }
            }
            
            /* 任务入队*/
            vEventWait(&mutex->event, curTask, (void *)0, OS_TASK_STA_WAIT_MUTEX, timeout);
            vTaskExitCritical(primask);
            
            vTaskYield();
            /* 任务返回时，在此执行*/
            
            return curTask->waitEventResult;
        }
    }
}


/*****************************************************************************
 * @function        vMutexNoWait
 * @brief 			非阻塞获取互斥锁.
 *  
 * @param[in] 		mutex 互斥锁.
 * 
 * @return 			获取结果.   	OS_NOERROR:获取成功
 *                           OS_ERROR_NORESOURCE: 获取失败
 *
 * ***************************************************************************/
uint32_t vMutexNoWait(MUTEX_T *mutex)
{
    uint32_t primask = vTaskEnterCritical();

    /* 无任务获取互斥锁*/
    if (mutex->lockCount == 0)
    {
        mutex->lockCount ++;
        mutex->owner = curTask;
        mutex->ownerOriginPrio = curTask->prio;     // 保存原始优先级
        
        vTaskExitCritical(primask);
        return OS_NOERROR;
    }
    else 
    {
        /* 互斥锁所有者 再次获取互斥锁*/
        if (curTask == mutex->owner)
        {
            mutex->lockCount++;
            vTaskExitCritical(primask);
            return OS_NOERROR;
        }
        /* 其他任务请求获取互斥锁*/
        else
        {
            vTaskExitCritical(primask);
            return OS_ERROR_NORESOURCE;
        }
    }
}

/*****************************************************************************
 * @function        vMutexNotify
 * @brief 			释放互斥锁.
 *  
 * @param[in] 		mutex 互斥锁.
 * 
 * @return 			释放结果.	 OS_NOERROR：释放成功
 *                  OS_ERROR_OWNER：非法释放者
 *
 * ***************************************************************************/
uint32_t vMutexNotify(MUTEX_T *mutex)
{
    TASK_T *task;
    
    uint32_t primask = vTaskEnterCritical();
    
    /* 无任务获取互斥锁，忽略通知*/
    if (mutex->lockCount == 0)
    {
        vTaskExitCritical(primask);
        return OS_NOERROR;
    }
    
    /* 非互斥锁所有者，进行通知，则错误*/
    if (curTask != mutex->owner)
    {
        vTaskExitCritical(primask);
        return OS_ERROR_OWNER;
    }
    
    /* 互斥锁本人调用*/
    if (--mutex->lockCount > 0)
    {
        vTaskExitCritical(primask);
        return OS_NOERROR;
    }
    
    /* 互斥锁本人调用， 且互斥锁计数值== 0*/
    /* 发生了优先级继承*/
    if (mutex->owner->prio != mutex->ownerOriginPrio)
    {
        /* 任务处于就绪态--恢复优先级*/
        if (mutex->owner->state == OS_TASK_STA_READY)
        {
            /* 将任务从就绪队列中移除，修改优先级后再添加进就绪队列中！！！*/
            vTaskReadyListDel(mutex->owner);
            mutex->owner->prio = mutex->ownerOriginPrio;
            vTaskReadyListAdd(mutex->owner);
        }
        /* 任务处于其他等待队列中,直接恢复优先级*/
        else 
        {
            mutex->owner->prio = mutex->ownerOriginPrio;
        }
    }
    
    /* 如果 互斥锁事件等待队列有任务*/
    if (vEventWaitCount(&mutex->event) )
    {
        /* 这里不对， 应该取优先级最高的互斥事件等待任务*/
        task = vEventWakeUp(&mutex->event, (void *)0, OS_NOERROR);
        
        mutex->owner = task;
        mutex->lockCount++;
        mutex->ownerOriginPrio = task->prio;

        if (task->prio < curTask->prio)
        {
            vTaskYield();
        }
    }

    vTaskExitCritical(primask);
    return OS_NOERROR;
}

/*****************************************************************************
 * @function        vMutexDestroy
 * @brief 			删除互斥锁. 将互斥锁中的所有等待任务移除，恢复 互斥锁所有者的优先级
 *  
 * @param[in] 		mutex 互斥锁.
 * 
 * @return 			移除的等待任务数量.	
 *
 * ***************************************************************************/
uint32_t vMutexDestroy(MUTEX_T *mutex)
{
    uint32_t count;
    
    uint32_t primask = vTaskEnterCritical();
    
    /* 如果互斥锁被使用*/
    if (mutex->lockCount)
    {
        /* 发生了优先级继承*/
        if (mutex->owner->prio != mutex->ownerOriginPrio)
        {
            /* 任务处于就绪态--恢复优先级*/
            if (mutex->owner->state == OS_TASK_STA_READY)
            {
                /* 将任务从就绪队列中移除，修改优先级后再添加进就绪队列中！！！*/
                vTaskReadyListDel(mutex->owner);
                mutex->owner->prio = mutex->ownerOriginPrio;
                vTaskReadyListAdd(mutex->owner);
            }
            /* 任务处于其他等待队列中,直接恢复优先级*/
            else 
            {
                mutex->owner->prio = mutex->ownerOriginPrio;
            }
        }
        
        /* 将等待队列中所有任务清除，至就绪队列中*/
        count = vEventRemoveAll(&mutex->event, (void *)0, OS_FORCE_DEL);
        
        vTaskExitCritical(primask);
        
        if (count )
        {
            vTaskYield();
        }
    
    }    
    return count;
}


/*****************************************************************************
 * @function        vMutexGetInfo
 * @brief 			获取互斥锁相关信息.
 *  
 * @param[in] 		mutex 互斥锁.
 * @param[out] 	    info 互斥锁信息控制块.
 * 
 * @return 			None.	
 *
 * ***************************************************************************/
void     vMutexGetInfo(MUTEX_T *mutex, MUTEX_INFO_T *info)
{
    uint32_t primask = vTaskEnterCritical();
    
    info->owner = mutex->owner;
    info->lockCount = mutex->lockCount;
    info->ownerNowPrio = mutex->owner->prio;
    info->ownerOriginPrio = mutex->ownerOriginPrio;
    info->taskCount = vEventWaitCount(&mutex->event);
    
    vTaskExitCritical(primask);
}

#endif // OS_ENABLE_MUTEX == 1
